package com.dems.task.job;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dems.dao.dataobject.ResDevice;
import com.dems.dao.mapper.la.ResDeviceMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import rk.netDevice.sdk.p3.*;

import javax.annotation.PostConstruct;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.List;

/**
 * @Description: TODO
 * @Date: 2023/6/2 13:49
 * @Version: 1.0.0
 */
@Component
@Slf4j
public class DeviceCollectListner {
    //登录接口
    private static final String BASE_URL = "https://dmp-https.cuiot.cn:8943/";

    private String singleDeviceUrl = "topic/sys/{productKey}/{deviceKey}/property/pub";

    //token过期时间24小时
    private Integer expireTime = 24;

    private long lastUpdateTime = 0;

    private String token = null;

    @Value("${gewu.upload.productKey:cuxps4gabsgt5l8c}")
    private String productKey;

    private Integer operator = 0;

    private String signMethod = "hmacsha256";

    private RestTemplate restTemplate;

    @Autowired
    private ResDeviceMapper resDeviceMapper;
    @Value("${gewu.listen.filePath}")
    private String filePath = "";
    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    @PostConstruct
    public void start() {
        new Thread(() -> {
            try {
                DeviceService.getInstance().addDataListener(new IDataListener() {
                    @Override
                    public void receiveLoginData(LoginData loginData) {
                        log.info("loginData:{}", JSON.toJSONString(loginData));
                    }

                    @Override
                    public void receiveTelecontrolAck(TelecontrolAck telecontrolAck) {
                        log.info("telecontrolAck:{}", JSON.toJSONString(telecontrolAck));
                    }

                    @Override
                    public void receiveRealTimeData(RealTimeData realTimeData) {
                        log.info("realTimeData:{}", JSON.toJSONString(realTimeData));
                        try {
                            uploadDeviceTask(realTimeData);
                        } catch (UnsupportedEncodingException e) {
                            throw new RuntimeException(e);
                        }
                    }

                    @Override
                    public void receiveStoreData(StoreData storeData) {
                        log.info("storeData:{}", JSON.toJSONString(storeData));
                    }

                    @Override
                    public void receiveStoreDataCount(StoreDataCount storeDataCount) {
                        log.info("storeDataCount:{}", JSON.toJSONString(storeDataCount));
                    }

                    @Override
                    public void receiveStoreDataAck(StoreDataAck storeDataAck) {
                        log.info("storeDataAck:{}", JSON.toJSONString(storeDataAck));
                    }

                    @Override
                    public void receiveTimingAck(TimingAck timingAck) {
                        log.info("timingAck:{}", JSON.toJSONString(timingAck));
                    }

                    @Override
                    public void receiveParamIds(ParamIds paramIds) {
                        log.info("paramIds:{}", JSON.toJSONString(paramIds));
                    }

                    @Override
                    public void receiveParamItems(ParamItems paramItems) {
                        log.info("paramItems:{}", JSON.toJSONString(paramItems));
                    }

                    @Override
                    public void receiveAffectedParamItems(AffectedParamItems affectedParamItems) {
                        log.info("affectedParamItems:{}", JSON.toJSONString(affectedParamItems));
                    }

                    @Override
                    public void receiveDataTransAck(DataTransAck dataTransAck) {
                        log.info("dataTransAck:{}", JSON.toJSONString(dataTransAck));
                    }
                });

                DeviceService.getInstance().setParamFile(this.filePath);
                DeviceService.getInstance().start("127.0.0.1", 8030);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }

    public void uploadDeviceTask(RealTimeData realTimeData) throws UnsupportedEncodingException {
        restTemplate = new RestTemplate();
        List<ResDevice> resDeviceList = resDeviceMapper.queryDeviceList(productKey);
        log.info("resDeviceList:{}", JSON.toJSONString(resDeviceList));
        for(ResDevice resDevice : resDeviceList) {
            int index = resDevice.getImei().indexOf("_");
            String deviceCode = resDevice.getImei().substring(0,index);
            String deviceId = resDevice.getImei().substring(index+1);
            log.info("deviceCode:{}, deviceAddr:{},deviceId:{}", deviceCode, realTimeData.getDeviceAddr(), deviceId);
            if(deviceCode.equals(realTimeData.getDeviceAddr().toString())) {
                long timestamp = System.currentTimeMillis();
                String deviceKey = resDevice.getDeviceKey();
                String deviceSecret = resDevice.getDeviceSecret();
                log.info("deviceSecret:{}", deviceSecret);
                if(token == null || ((timestamp-lastUpdateTime) > expireTime*60*60*1000L)){
                    token = this.getToken(deviceKey, deviceSecret, deviceId, timestamp);
                    lastUpdateTime = timestamp;
                }
                log.info("token:{}", token);
                singleDeviceUrl = singleDeviceUrl.replace("{productKey}", productKey).replace("{deviceKey}", deviceKey);
                String reqUrl = BASE_URL + singleDeviceUrl;
                int seqNo = 0;
                for (NodeData nodeData : realTimeData.getNodeDataList()) {
                    JSONObject reqParam = new JSONObject();
                    reqParam.put("messageId", seqNo++);
                    JSONObject param = new JSONObject();
                    if (nodeData.getNodeId() == 1) {
                        param.put("key", "currentTemperature");
                        param.put("value", nodeData.getData());
                    }
                    if (nodeData.getNodeId() == 3) {
                        param.put("key", "powerSwitch");
                        param.put("value", nodeData.getData());
                    }
                    if (nodeData.getNodeId() == 4) {
                        param.put("key", "setTemperature");
                        param.put("value", nodeData.getData());
                    }
                    param.put("ts", nodeData.getRecordTime() * 1000L);
                    reqParam.put("params", param);
                    log.info("reqParam:{}", reqParam);
                    HttpEntity<?> request = buildHttpEntity(token, reqParam);
                    String responseStr = restTemplate.postForObject(reqUrl, request, String.class);
                    log.info("upload response{}", responseStr);
                }
            }
        }
    }

    private String getToken(String deviceKey, String deviceSecret, String deviceId, long timestamp){
        restTemplate = new RestTemplate();
        StringBuffer data = new StringBuffer();
        data.append(deviceId).append(deviceKey).append(productKey).append(signMethod).append(operator).append(timestamp);
        String sign = TokenUtil.hmacMD5(deviceSecret, data.toString());
        JSONObject requestParam = new JSONObject();
        requestParam.put("productKey", productKey);
        requestParam.put("deviceKey", deviceKey);
        requestParam.put("operator", operator);
        requestParam.put("deviceId", deviceId);
        requestParam.put("timestamp", timestamp);
        requestParam.put("signMethod", signMethod);
        requestParam.put("sign", sign);
        HttpEntity<?> request = buildHttpEntity(requestParam);
        String responseStr = restTemplate.postForObject(BASE_URL+"auth", request, String.class);
        log.info("auth response:{}", responseStr);
        String token = JSON.parseObject(responseStr).getJSONObject("data").getString("token");
        return token;
    }

    public HttpEntity<Object> buildHttpEntity(JSONObject param) {
        HttpHeaders requestHeaders = new HttpHeaders();
        // Authorization: `Bearer:${token}`
        requestHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
        requestHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8);
        return new HttpEntity<>(param, requestHeaders);
    }

    public HttpEntity<Object> buildHttpEntity(String token, JSONObject param) throws UnsupportedEncodingException {
        HttpHeaders requestHeaders = new HttpHeaders();
        requestHeaders.set("Authorization", token);
        //requestHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
        requestHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        byte[] reqBytes = param.toString().getBytes("UTF-8");
        return new HttpEntity<>(reqBytes, requestHeaders);
    }
}
